package com.crawler.waf.security.services.impl;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.crawler.waf.config.WafProperties;
import com.crawler.waf.security.authens.BaseUserInfo;
import com.crawler.waf.security.authens.UserRole;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

/**
 * 用户信息获取缓存类

 */
public class UserCenterUserDetailsCacheService extends UserCenterUserDetailsService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static LoadingCache<String, List<UserRole>> userRoleCache;

    private static LoadingCache<String, BaseUserInfo> userInfoCache;

    public static final String UC_CACHE_EXPIRE = "uc.cache.expire";
    public static final String UC_CACHE_MAX_SIZE = "uc.cache.maxSize";

    /**
     * 调用父类获取用户角色信息的方法
     *
     * @param userId
     * @param realm
     * @return
     */
    private List<UserRole> getUserRoleListInner(String userId) {
        return super.getUserRoleList(userId);
    }

    /**
     * 调用父类获取用户信息的方法
     *
     * @param userId
     * @param realm
     * @return
     */
    private BaseUserInfo getUserInfoInner(String userId) {
        return super.getUserInfo(userId);
    }

    /**
     * 初始化userRole cache
     */
    private void initUserRoleCache() {
        if (userRoleCache == null) {
            synchronized (this) {
                if (userRoleCache == null) {
                    userRoleCache = CacheBuilder.newBuilder()
                            .maximumSize(WafProperties.getPropertyForInteger(UC_CACHE_MAX_SIZE,"10000"))
                            .expireAfterWrite(WafProperties.getPropertyForInteger(UC_CACHE_EXPIRE,"20"), TimeUnit.MINUTES)
                            .build(new CacheLoader<String, List<UserRole>>() {
                                @Override
                                public List<UserRole> load(String userId)
                                        throws Exception {
                                    if (!StringUtils.isEmpty(userId)) {
                                        return getUserRoleListInner(userId);
                                    } else {
                                        throw new IllegalArgumentException("initUserRoleCache 方法在获取 userId的过程发生异常。");
                                    }
                                }
                            });
                }
            }
        }
    }

    /**
     * 初始化userinfo cache
     */
    private void initUserInfoCache() {
        if (userInfoCache == null) {
            synchronized (this) {
                if (userInfoCache == null) {
                    userInfoCache = CacheBuilder.newBuilder()
                            .maximumSize(10000)
                            .expireAfterWrite(20, TimeUnit.MINUTES)
                            .build(new CacheLoader<String, BaseUserInfo>() {
                                @Override
                                public BaseUserInfo load(String userId) throws Exception {
                                	if (!StringUtils.isEmpty(userId)) {
                                        return getUserInfoInner(userId);
                                    } else {
                                        throw new IllegalArgumentException("initUserInfoCache 方法在获取 userId 的过程发生异常。");
                                    }
                                }
                            });
                }
            }
        }
    }

    /**
     * 获取用户用户角色信息
     *
     * @return
     */
    public List<UserRole> getUserRoleList(String userId) {
        this.initUserRoleCache();
        try {
            return userRoleCache.get(userId);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 向UC发送获取用户信息的请求
     *
     * @return
     */
    public BaseUserInfo getUserInfo(String userId) {
        this.initUserInfoCache();

        try {
            return userInfoCache.get(userId);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}
